package com.tianji.learning.task;

import cn.hutool.core.util.ObjectUtil;
import com.tianji.common.utils.DateUtils;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.service.IPointsBoardSeasonService;
import com.tianji.learning.service.IPointsBoardService;
import com.tianji.learning.utils.TableInfoContext;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

import static com.tianji.learning.constants.LearningConstants.POINTS_BOARD_TABLE_PREFIX;
import static com.tianji.learning.constants.RedisConstants.POINTS_BOARD_KEY_PREFIX;

/**
 * @author Administrator
 * @version 1.0
 * @description: TODO
 * @date 2024/7/1 14:53
 */
@Component
@RequiredArgsConstructor
public class PointsBoardPersistentTask {
    private final IPointsBoardSeasonService pointsBoardSeasonService;
    private final IPointsBoardService pointsBoardService;
    private final StringRedisTemplate redisTemplate;

    /**
     * 创建上一个赛季积分排行榜表
     */
    @XxlJob("createTableJob")
    public void createPointsBoardTableOfLastSeason() {
        // 1、获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);

        // 2、查询赛季ID
        Integer seasonId = pointsBoardSeasonService.querySeasonByTime(time);

        // 3、创建表
        pointsBoardService.createPointsBoardTableBySeasonId(seasonId);
    }

    /**
     * 持久化redis中的榜单数据至数据库
     */
    @XxlJob("savePointsBoard2DB")
    public void savePointsBoard2DB() {
        // 1、获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);

        // 2、计算动态表名
        // 2.1、查询赛季ID
        Integer seasonId = pointsBoardSeasonService.querySeasonByTime(time);

        // 2.2、拼接表名，存入ThreadLocal
        TableInfoContext.setInfo(POINTS_BOARD_TABLE_PREFIX + seasonId);

        // 3、查询redis中的榜单数据
        // 3.1、拼接key （boards:202407）
        String key = POINTS_BOARD_KEY_PREFIX + time.format(DateUtils.DATE_SUFFIX_FORMATTER);

        // 3.2、查询redis榜单数据
        int index = XxlJobHelper.getShardIndex();  // 当前实例的xxljob分片序号
        int total = XxlJobHelper.getShardTotal();  // xxljob总分片数
        int pageNo = index + 1,pageSize = 2;
        while(true) {
            List<PointsBoard> boardList = pointsBoardService.queryCurrentBoardList(key, pageNo, pageSize);
            if(ObjectUtil.isEmpty(boardList)){
                break;
            }
            // 4、持久化数据到数据库
            boardList.forEach(board -> {
                board.setId(board.getRank().longValue());
                board.setRank(null);
            });
            pointsBoardService.saveBatch(boardList);

            // 5、翻页
            pageNo += total;
        }

        // 6、清理ThreadLocal，防止内存泄漏
        TableInfoContext.remove();
    }


    /**
     * 清理redis zset中的榜单数据
     */
    @XxlJob("clearPointsBoardFromRedis")
    public void clearPointsBoardFromRedis() throws InterruptedException {
        Thread.sleep(10000L);
        // 1、获取上月时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);

        // 2、计算key
        String key = POINTS_BOARD_KEY_PREFIX + time.format(DateUtils.DATE_SUFFIX_FORMATTER);

        // 3、删除(异步删除，非阻塞的)
        redisTemplate.unlink(key);
        // 大key的影响
            // 1、数据倾斜
            // 2、影响查询性能
            // 3、影响主从同步效率
    }
}
